GHood – Graphical Visualisation and Animation of Haskell Object Observations

نویسنده

  • Claus Reinke
چکیده

As a possible extension to his Haskell Object Observation Debugger Hood [7], Andy Gill has described the “dynamic viewing of structures”, stepping through observations instead of accumulating them into a static view. Starting from this idea, we have implemented and released an animation back-end for Hood, called GHood. Instead of the dynamic textual visualisation based on pretty-printing proposed in [7], our back-end features a dynamic graphical visualisation, based on a simple tree layout algorithm. This paper reviews the main aspects of Hood, gives a brief introduction to GHood’s features and summarises our experience so far. The visualisation of program behaviour via animations of data structure observations has uses for program comprehension and exposition, in development, debugging and education. We find that the graphical structure facilitates orientation even when textual labels are no longer readable due to scaling, suggesting advantages over a purely textual visualisation. A novel application area is opened by the use of GHood as an applet on web pages – discussions of Haskell program behaviour, e.g., in educational online material or in explanations of functional algorithms, can now easily be augmented with graphical animations of the issues being discussed. 1 Well-typed programs don’t go anywhere – or do they? The war-cry of static typing is that “well-typed programs don’t go wrong”, but sometimes the question is “where does this well-typed program go?”, requiring a more detailed understanding of program behaviour. For a surprisingly long time, Haskell programmers have been deprived of tools that would enable them to investigate the behaviour of their programs at a suitable level of abstraction. This lack of tool support, especially in the areas of debugging and profiling, has been quoted as one of the reasons “why no one uses functional languages” [18]. In the context of Haskell profiling, the lack has 1 mailto:[email protected] http://www.cs.ukc.ac.uk/people/staff/cr3/ 121 Reinke not been felt quite so urgently, because increasingly sophisticated lower-level tools have continued to appear (support still varies between implementations, though, and tools are implementation-specific). Still, there is a discrepancy: if programs are written in a nice high-level language, why do their dynamic aspects have to be studied in low-level terms of stackand heap-usage? And in the area of debugging, the situation has only just started to improve. A recent survey [3] compares three tools for tracing and debugging of lazy functional programs: Hat [20], Freja [13], and Hood [7]. All of these systems offer inspection facilities at a level close to the programming language, based on different forms of execution traces, and can be characterised on the basis of the questions they help to answer. Hat 2 takes wrong program output as starting points, enabling users to trace backwards through reduction sequences (“where did this result or output come from?”). Freja supports a technique known as declarative debugging, involving users in a dialogue that narrows down to the source of errors (“this part of your program gives the following result. Is this correct (yes/no)?”). For Hood, it is useful to imagine a data-flow model of functional program execution, with parameters flowing into operators or functions and results flowing out. On this basis, programmers can use Hood to insert probes into their programs to monitor or observe the flow of data at runtime (“what kind of data structure is flowing through here?”). Tracing tools offer high-level views into Haskell program executions. Focusing on different aspects of program behaviour, the existing tools complement each other, but it turns out that they all provide essentially static views of program execution traces, highlighting logical connections between intermediate terms instead of execution dynamics. As a possible extension to Hood, Andy Gill described the “dynamic viewing of structures”, stepping through observations using a textual form of visualisation based on pretty-printing [7]. Gill implemented and demonstrated a browser back-end for Hood, based on this idea (the back-end itself is available from the Haskell CVS repository, but it is not supported by the Hood observation library, as released in July 2000; that Haskell library implements the observation combinator by accumulating observations and printing a static view at the end of program runs). We are here concerned with extending the usefulness of Hood (the most recent of these tools, and also the only implementation-independent one) by adding dynamic views of observation traces. Starting from Gill’s idea, and building on the Hood observation library, we have implemented and released a graphical animation back-end for Hood, called GHood. Instead of a dynamic textual visualisation based on pretty-printing, our back-end features a dynamic graphical visualisation, based on a simple tree layout algorithm. After reviewing the main aspects of Hood, this paper gives a brief introduction to GHood’s features, demonstrates some of the new applications enabled by GHood by way of two small examples, and summarises our experience so far. 2 Hat has since been extended considerably, and now supports several models of tracing, implemented on top of a single program execution trace (cf. Section 5.1, as well as [19,20]). 122 Reinke 2 Hood – goodbye trace, hello observe The pseudo-function trace :: String -> a -> a – not part of any Haskell language definition, but supported by all Haskell implementations – is supposed to be acting as an identity with a String-label. When evaluated, it returns its second parameter, but also prints its label as a side-effect. Reminiscent of the print-statements with which imperative programmers inspect their programs in the absence of proper debuggers, side-effecting output can thus be used to generate a trace of the execution of a Haskell program. But in the end, unconstrained use of side-effecting input/output operations is no more suitable for debugging than for any other kind of input/output in a lazy functional language. Functional input/output has moved on to more systematic, declarative means of expression, which require to make effects visible in the structure, and thus in the type of programs (Chapter 3 of [16] aims to give a logical reconstruction of the main lines in this development). But this is exactly what prevents the use of these more structured means of input/output for debugging purposes, where one wants to inspect the behaviour of a given program, without having to restructure it into something else first. Enter Hood (Haskell Object Observation Debugger). One way of understanding Hood is via a line of reasoning similar to that which led to today’s functional input/output systems – it is not the idea of side-effecting operations that is at fault, it is their undisciplined use that causes problems. As the requirements of debugging differ from those of standard input/output, a similar line of reasoning will not necessarily lead to similar solutions. In standard usage, input/output is part of the program and should be reflected in its type structure whereas, for debugging purposes, the input/output-operations are part of the workbench used to inspect the program, and the original program should be disturbed as little as possible. Developing this idea, Hood consists of a fairly complex library with a relatively simple interface. In fact, the type of the major function has not changed much: observe :: Observable a => String -> a -> a. Similar to trace, observe acts as an identity with a String label. But the similarities end here – calls to trace effectively imitate imperative print-statements, whereas calls to observe capture the intention behind print-style-debugging (indicating interest in intermediate values) in a declarative way, leaving the “how” of capturing and presenting information to the implementation. The combination of observe and its observation and presentation library eliminates all the major deficiencies of trace: (i) (a) With trace, all information is communicated via the String parameter. Programmers have to add code to inspect parts of their program, and to incorporate the inspection results into the String labels. (b) With observe, instances of the Observable class handle all aspects of program inspection, offering a much more convenient high-level interface. The String parameter is just used as a label. 123 Reinke (ii) (a) The extra inspection code needed to feed information into trace labels implies non-trivial program modifications, which run the risk of introducing bugs and changing strictness properties in the process. (b) Predefined instances for most standard types and a combinator approach to user-defined instances of Observable imply smaller program modifications and ensure that strictness properties of the program under inspection are not affected by the use of observe. (iii) (a) When evaluated, trace immediately attempts to output its label. Under a lazy evaluation strategy, this may cause other traced expressions to be evaluated, and the order of output can be confusing. (b) Evaluation of observe causes information to be captured, but this is decoupled from presentation and output. In Hood, the observation events are post-processed when the observed program has terminated – observations are grouped by their labels into comprehensive summaries, which are pretty-printed as partially-known data structures. For the full details, readers are referred to the Hood paper and documentation [7,8], but for a two-parameter constructor C in an algebraic data type, the general mechanism can be illustrated by the following pseudo-code: observer (C x y) = λposition -> unsafePerformIO $ do sendEvent return (C (observer x position.0) (observer y position.1)) where observer is a helper function called by observe (initialising position), and position records the position of the current subexpression in the observed data structure. The definition is strict in the observed (sub-)structure, forcing its evaluation to weak head normal form, but only if the weak head normal form of the whole expression is required by the evaluation context. On this occasion, the observer generates an observation event, tagged with the position information, wraps any constructor parameters in new observers, and returns the observed constructor to the evaluation context. All those implementation details are hidden behind suitable monads and combinators, offering a simple user-level interface, and observers for most standard types are predefined. The (predefined) instance of Observable for lists may serve to illustrate that it is straightforward, if somewhat tedious, to make new types observable: instance (Observable a) => Observable [a] where observer (a:as) = send ":" (return (:) << a << as) observer [] = send "[]" (return []) Using observe is equally straightforward (runO :: IO a -> IO () runs an IO-script while taking care of observation event processing): import Observe main = runO $ print $ observe "just a list" [1..4::Int]

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

منابع مشابه

Warping to Enhance 3D User Interfaces

Cartoon animation techniques have previously been used to enhance the illusion of direct manipulation in 2D graphical user interfaces. In particular, animation may be used to convey a feeling of substance to the objects being manipulated by the user. This paper presents an expansion of this concept to 3D graphical object manipulation. A standard set of 3D direct manipulation operations have bee...

متن کامل

Visualisation for Validation

Animation is a multiple graphical view of a process in action. Animation has been successfully employed in programming for designing, developing and debugging programs or monitoring their performance. This paper advocates that many benefits can be accrued from the use of visualisation techniques for the purpose of validating conceptual specifications during Requirements Engineering. To this end...

متن کامل

Visualisation of route descriptions in a resource-adaptive navigation aid

2 In our current research project REAL, which is part of the special research program 378 `Resource adaptive cognitive processes', we are building a resource adaptive navigational help system. The system can generate multi-modal graphical route descriptions for different output devices, and has the ability to adapt to various restricted resources during the generation of graphical route descrip...

متن کامل

Visualisation of conceptual specifications

The development of a large information system is generally regarded as one of the most complex activities undertaken by organisations. A key factor to the success of this activity is improvements in communication and understanding among the actors of the system (i.e. managers, developers, etc.). Accordingly, a crucial factor is the level of support provided for the interaction process between t...

متن کامل

Jaroslaw Francik Data Flow Tracing for Algorithm Animation

Software visualisation consists of applying various multimedia techniques for significant improvement of human understanding of computer software. If the subject of such visualisation is an algorithm, and computer generated animation is essential for its realisation, we say of algorithm animation. Successful algorithm visualisations usually go beyond isomorphic mappings of program data or code ...

متن کامل

ذخیره در منابع من


  با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

عنوان ژورنال:

دوره   شماره 

صفحات  -

تاریخ انتشار 2001